למדו לבנות ארנק קריפטו מאובטח מאפס עם פייתון. מדריך מעמיק זה מכסה מושגי מפתח, קריפטוגרפיה, ספריות ודוגמאות קוד מעשיות.
בניית ארנק מטבעות קריפטוגרפיים בפייתון: מדריך מקיף
בעולם הפיננסים הדיגיטלי המתפתח במהירות, מטבעות קריפטוגרפיים הגיחו ככוח משנה-מציאות. בלב המהפכה הזו טמון הרעיון של ארנק – השער האישי שלך לאינטראקציה עם רשתות בלוקצ'יין. בעוד שקיימים ארנקים מסחריים רבים, הבנת אופן פעולתם "מתחת למכסה המנוע" היא מיומנות שלא יסולא בפז עבור כל מפתח או חובב טכנולוגיה. מדריך זה יסיר את המסתורין מהתהליך על ידי הדרכה ביצירת ארנק מטבעות קריפטוגרפיים פונקציונלי מאפס באמצעות פייתון.
נסקור את העקרונות הקריפטוגרפיים הבסיסיים, ספריות פייתון חיוניות, ואת ההטמעה צעד אחר צעד ליצירת מפתחות, יצירת כתובות הן לביטקוין והן לאתריום, וחתימה על עסקאות. בסיום מאמר זה, תהיה לכם הבנה מוצקה של מכניקת הארנק וארנק שורת פקודה עובד משלכם.
כתב ויתור: הקוד והמושגים המוצגים במדריך זה הם למטרות לימוד בלבד. בניית ארנק ברמת ייצור דורשת ביקורות אבטחה קפדניות, בדיקות נרחבות ואמצעי אבטחה מתקדמים. אין להשתמש בארנק שנוצר כאן לאחסון כספים אמיתיים.
הבנת מושגי הליבה של ארנק מטבעות קריפטוגרפיים
לפני שנכתוב שורת קוד אחת, חשוב להבין מהו באמת ארנק מטבעות קריפטוגרפיים. בניגוד לשמו, ארנק אינו "אוגר" את המטבעות שלך. המטבע הקריפטוגרפי שלך קיים כרשומות על פנקס מבוזר – הבלוקצ'יין. ארנק הוא פיסת תוכנה המנהלת את המפתחות הקריפטוגרפיים המעניקים לך בעלות ושליטה על הנכסים שלך באותו פנקס.
המרכיבים העיקריים של כל ארנק שאינו משמורתי הם:
1. מפתחות פרטיים: הסוד הדיגיטלי שלך
מפתח פרטי הוא פיסת המידע הקריטית ביותר בארנק שלך. זהו מספר גדול מאוד, שנוצר באופן אקראי, נשמר בסוד וידוע רק לך. מטרתו היא ליצור חתימה דיגיטלית, המשמשת כהוכחה בלתי ניתנת לערעור שאישרת עסקה. אם תאבד את המפתח הפרטי שלך, תאבד לנצח את הגישה לכספים שלך. אם מישהו אחר יקבל גישה אליו, תהיה לו שליטה מלאה על כספיך.
- אנלוגיה: חשבו על מפתח פרטי כמפתח האב לכספת הדיגיטלית שלכם. הוא יכול לפתוח את הכספת ולאשר את העברת תכולתה.
2. מפתחות ציבוריים: המזהה הניתן לשיתוף שלך
מפתח ציבורי נגזר מתמטית מהמפתח הפרטי שלך באמצעות פונקציה קריפטוגרפית חד-כיוונית המכונה קריפטוגרפיה על עקומים אליפטיים (ECC). בעוד שניתן ליצור מפתח ציבורי ממפתח פרטי, זה בלתי אפשרי מבחינה חישובית לעשות את הפעולה ההפוכה. קשר חד-כיווני זה הוא הבסיס לאבטחת מטבעות קריפטוגרפיים.
- אנלוגיה: מפתח ציבורי הוא כמו מספר חשבון הבנק שלך. אתה יכול לשתף אותו עם אחרים כדי שיוכלו לשלוח לך כסף, אבל הוא לא נותן להם את היכולת למשוך כספים.
3. כתובות: היעד הציבורי שלך
כתובת ארנק היא ייצוג קצר יותר וידידותי יותר למשתמש של המפתח הציבורי שלך. היא נוצרת על ידי הפעלת אלגוריתמי גיבוב נוספים (כמו SHA-256 ו-RIPEMD-160) על המפתח הציבורי ולעתים קרובות כוללת בדיקת סכום (checksum) למניעת שגיאות הקלדה בעת שליחת כספים. זוהי מחרוזת התווים שאתה משתף עם אחרים כדי לקבל מטבע קריפטוגרפי.
- אנלוגיה: אם המפתח הציבורי הוא מספר חשבונך, הכתובת היא כמו מספר חשבונית ספציפי ומעוצב הכולל תכונות בדיקת שגיאות.
4. הקישור הקריפטוגרפי: רחוב חד-סטרי
הקשר בין רכיבים אלה הוא היררכיה קפדנית, חד-כיוונית:
מפתח פרטי ← מפתח ציבורי ← כתובת
עיצוב זה מבטיח שתוכל לשתף בבטחה את כתובתך מבלי לחשוף ישירות את המפתח הציבורי שלך (במקרים מסוימים) ובטח מבלי לחשוף אי פעם את המפתח הפרטי שלך.
5. חתימות דיגיטליות: הוכחת הבעלות
כאשר ברצונך לשלוח מטבע קריפטוגרפי, אתה יוצר הודעת עסקה (לדוגמה, "שלח 0.5 BTC מכתובת A לכתובת B"). תוכנת הארנק שלך משתמשת אז במפתח הפרטי שלך כדי ליצור חתימה דיגיטלית ייחודית עבור אותה עסקה ספציפית. חתימה זו משודרת לרשת יחד עם העסקה. כורים וצמתים ברשת יכולים להשתמש במפתח הציבורי שלך כדי לאמת שהחתימה תקפה, ולאשר שהעסקה אושרה על ידי הבעלים הלגיטימי של הכספים מבלי לראות את המפתח הפרטי שלך לעולם.
הגדרת סביבת הפיתוח שלך בפייתון
כדי לבנות את הארנק שלנו, נזדקק למספר ספריות פייתון מיוחדות המטפלות בקריפטוגרפיה המורכבת הכרוכה בכך. ודא שהתקנתם פייתון 3.6 או חדש יותר. ניתן להתקין את החבילות הנדרשות באמצעות pip:
pip install ecdsa pysha3 base58
בואו נפרט מה עושה כל ספרייה:
- ecdsa: זוהי ספרייה חיונית ליישום אלגוריתם החתימה הדיגיטלית על עקומים אליפטיים (ECDSA). נשתמש בה כדי ליצור מפתחות פרטיים וציבוריים המבוססים על העקום
SECP256k1, שהוא התקן המשמש את ביטקוין, אתריום ומטבעות קריפטוגרפיים רבים אחרים. היא מטפלת גם ביצירה ובאימות של חתימות דיגיטליות. - pysha3: בעוד שספריית
hashlibהמובנית של פייתון תומכת באלגוריתמי גיבוב רבים, היא אינה כוללת את Keccak-256, הנדרש ליצירת כתובות אתריום. ספרייה זו מספקת פונקציונליות זו. - base58: ספרייה זו מיישמת קידוד Base58Check, פורמט המשמש ליצירת כתובות ביטקוין קריאות-אדם. היא כוללת בדיקת סכום למניעת שגיאות הקלדה.
- hashlib: ספריית פייתון מובנית זו תשמש לגיבוב SHA-256 ו-RIPEMD-160, שהם שלבים חיוניים ביצירת כתובת ביטקוין.
הטמעה צעד אחר צעד: בניית לוגיקת הארנק
עכשיו, בואו נצלול לקוד. נבנה את פונקציות הליבה של הארנק שלנו פיסה אחר פיסה, ונסביר כל שלב לאורך הדרך.
שלב 1: יצירת מפתח פרטי
מפתח פרטי הוא למעשה מספר בן 256 ביט (32 בתים). הדרישה החשובה ביותר היא שחובה ליצור אותו באקראיות אמיתית. שימוש במחולל מספרים אקראיים חלש עלול להוביל למפתחות צפויים שתוקף יוכל לנחש.
מודול ה-secrets המובנה של פייתון מיועד ליצירת מספרים אקראיים מאובטחים קריפטוגרפית, מה שהופך אותו למושלם לצרכינו.
import os
import hashlib
import base58
import ecdsa
from sha3 import keccak_256
def generate_private_key():
"""Generate a secure 32-byte private key."""
private_key_bytes = os.urandom(32)
return private_key_bytes
כאן, `os.urandom(32)` מספק 32 בתים אקראיים מאובטחים קריפטוגרפית, וזה בדיוק מה שאנו צריכים עבור מפתח פרטי בן 256 ביט.
שלב 2: גזירת המפתח הציבורי
לאחר מכן, אנו גוזרים את המפתח הציבורי מהמפתח הפרטי באמצעות העקום האליפטי `SECP256k1`. ספריית `ecdsa` הופכת תהליך זה לפשוט.
def private_key_to_public_key(private_key_bytes):
"""Convert a private key to its corresponding public key."""
# SECP256k1 is the curve used by Bitcoin and Ethereum
sk = ecdsa.SigningKey.from_string(private_key_bytes, curve=ecdsa.SECP256k1)
# Get the public key in uncompressed format (starts with 0x04)
vk = sk.verifying_key
public_key_bytes = vk.to_string("uncompressed")
return public_key_bytes
אובייקט `ecdsa.SigningKey` מייצג את המפתח הפרטי שלנו. לאחר מכן אנו מקבלים את ה-`verifying_key` (מפתח ציבורי) המתאים ומייצאים אותו בפורמט "לא דחוס". מפתח ציבורי לא דחוס הוא באורך 65 בתים: קידומת `0x04` ואחריה קואורדינטת X באורך 32 בתים וקואורדינטת Y באורך 32 בתים של נקודה על העקום האליפטי.
שלב 3: יצירת כתובת ביטקוין
יצירת כתובת ביטקוין ממפתח ציבורי היא תהליך רב-שלבי המיועד לאבטחה ובדיקת שגיאות. הנה זרימת יצירת כתובת P2PKH (Pay-to-Public-Key-Hash) הסטנדרטית:
- גיבוב SHA-256: גבב את המפתח הציבורי באמצעות SHA-256.
- גיבוב RIPEMD-160: גבב את תוצאת השלב הקודם באמצעות RIPEMD-160.
- הוסף בייט גרסה: הוסף קידומת בייט גרסה לגיבוב RIPEMD-160. עבור רשת הביטקוין הראשית (mainnet), זהו `0x00`.
- חישוב בדיקת סכום: בצע גיבוב SHA-256 על הגיבוב המורחב פעמיים, וקח את 4 הבתים הראשונים של הגיבוב הסופי. זהו בדיקת הסכום.
- צרף בדיקת סכום: צרף את בדיקת הסכום באורך 4 בתים לסוף הגיבוב המוגדל בגרסה.
- קידוד Base58Check: קודד את כל מחרוזת הבתים באמצעות Base58Check כדי לקבל את הכתובת הסופית, הקריאה לאדם.
בואו נטמיע זאת בפייתון:
def public_key_to_btc_address(public_key_bytes):
"""Convert a public key to a Bitcoin P2PKH address."""
# Step 1 & 2: SHA-256 then RIPEMD-160
sha256_hash = hashlib.sha256(public_key_bytes).digest()
ripemd160_hash = hashlib.new('ripemd160')
ripemd160_hash.update(sha256_hash)
hashed_public_key = ripemd160_hash.digest()
# Step 3: Add version byte (0x00 for Mainnet)
version_byte = b'\x00'
versioned_hash = version_byte + hashed_public_key
# Step 4 & 5: Create checksum and append
# Double SHA-256 hash
checksum_hash_1 = hashlib.sha256(versioned_hash).digest()
checksum_hash_2 = hashlib.sha256(checksum_hash_1).digest()
checksum = checksum_hash_2[:4]
binary_address = versioned_hash + checksum
# Step 6: Base58Check encode
btc_address = base58.b58encode(binary_address).decode('utf-8')
return btc_address
שלב 4: יצירת כתובת אתריום
יצירת כתובת אתריום פשוטה יותר בהשוואה לביטקוין. היא כוללת לקיחת גיבוב Keccak-256 של המפתח הציבורי ושימוש ב-20 הבתים האחרונים של התוצאה.
- גיבוב Keccak-256: קח את גיבוב Keccak-256 של המפתח הציבורי. שים לב שעלינו להשתמש במפתח הציבורי *ללא* הקידומת `0x04`.
- קח את 20 הבתים האחרונים: כתובת האתריום היא 20 הבתים האחרונים (40 תווים הקסדצימליים) של גיבוב זה.
- פורמט: נהוג להוסיף לכתובת את הקידומת `0x`.
בואו נטמיע זאת באמצעות `pysha3`:
def public_key_to_eth_address(public_key_bytes):
"""Convert a public key to an Ethereum address."""
# Ethereum address generation uses the uncompressed public key without the 0x04 prefix
uncompressed_pk = public_key_bytes[1:]
# Step 1: Keccak-256 hash
keccak_hash = keccak_256(uncompressed_pk).digest()
# Step 2: Take the last 20 bytes
eth_address_bytes = keccak_hash[-20:]
# Step 3: Format with '0x' prefix
eth_address = '0x' + eth_address_bytes.hex()
return eth_address
שלב 5: חתימה על הודעה
חתימה דיגיטלית מוכיחה שבעל מפתח פרטי אישר הודעה (כגון עסקה). התהליך כולל חתימה על גיבוב ההודעה, ולא על ההודעה הגולמית עצמה, מטעמי יעילות ואבטחה.
def sign_message(private_key_bytes, message):
"""Sign a message with the given private key."""
# It's standard practice to sign the hash of the message
message_hash = hashlib.sha256(message.encode('utf-8')).digest()
sk = ecdsa.SigningKey.from_string(private_key_bytes, curve=ecdsa.SECP256k1)
signature = sk.sign(message_hash)
return signature
שלב 6: אימות חתימה
אימות הוא התהליך ההפוך. כל מי שיש לו את המפתח הציבורי, ההודעה המקורית והחתימה יכול לאשר שהחתימה אותנטית. כך רשת הבלוקצ'יין מאמתת עסקאות.
def verify_signature(public_key_bytes, signature, message):
"""Verify a signature for a message with the given public key."""
message_hash = hashlib.sha256(message.encode('utf-8')).digest()
vk = ecdsa.VerifyingKey.from_string(public_key_bytes, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256)
try:
# The verify method will return True if valid, or raise an exception
return vk.verify(signature, message_hash)
except ecdsa.BadSignatureError:
return False
הרכבת הארנק: ממשק שורת פקודה פשוט (CLI)
כעת, לאחר שיש לנו את כל פונקציות הליבה, בואו נחבר אותן לכלי פשוט ושימושי בשורת הפקודה. ניצור מחלקת `Wallet` כדי לעטוף את הלוגיקה ונשתמש במודול `argparse` של פייתון לטיפול בפקודות המשתמש.
הנה סקריפט שלם המשלב את כל הפונקציות שלנו ליישום קוהרנטי.
#!/usr/bin/env python3
import os
import hashlib
import base58
import ecdsa
import argparse
from sha3 import keccak_256
class Wallet:
"""Represents a cryptocurrency wallet with key management and address generation."""
def __init__(self, private_key_hex=None):
if private_key_hex:
self.private_key = bytes.fromhex(private_key_hex)
else:
self.private_key = self._generate_private_key()
self.public_key = self._private_to_public_key(self.private_key)
self.btc_address = self._public_to_btc_address(self.public_key)
self.eth_address = self._public_to_eth_address(self.public_key)
def _generate_private_key(self):
return os.urandom(32)
def _private_to_public_key(self, private_key):
sk = ecdsa.SigningKey.from_string(private_key, curve=ecdsa.SECP256k1)
return sk.verifying_key.to_string("uncompressed")
def _public_to_btc_address(self, public_key):
sha256_hash = hashlib.sha256(public_key).digest()
ripemd160 = hashlib.new('ripemd160')
ripemd160.update(sha256_hash)
hashed_pk = ripemd160.digest()
versioned_hash = b'\\x00' + hashed_pk
checksum = hashlib.sha256(hashlib.sha256(versioned_hash).digest()).digest()[:4]
binary_address = versioned_hash + checksum
return base58.b58encode(binary_address).decode('utf-8')
def _public_to_eth_address(self, public_key):
uncompressed_pk = public_key[1:]
keccak_hash = keccak_256(uncompressed_pk).digest()
return '0x' + keccak_hash[-20:].hex()
def display_details(self):
print(f"Private Key (hex): {self.private_key.hex()}")
print(f"Public Key (hex): {self.public_key.hex()}")
print(f"Bitcoin Address: {self.btc_address}")
print(f"Ethereum Address: {self.eth_address}")
def main():
parser = argparse.ArgumentParser(description="A simple command-line cryptocurrency wallet.")
parser.add_argument("command", choices=["create", "details"], help="The command to execute.")
parser.add_argument("--privatekey", help="An existing private key in hex format to get details from.")
args = parser.parse_args()
if args.command == "create":
wallet = Wallet()
print("--- New Wallet Created ---")
wallet.display_details()
print("\\n*** IMPORTANT ***")
print("Save your private key in a secure location. It is the only way to access your funds.")
elif args.command == "details":
if not args.privatekey:
print("Error: The 'details' command requires a private key using the --privatekey flag.")
return
try:
wallet = Wallet(private_key_hex=args.privatekey)
print("--- Wallet Details ---")
wallet.display_details()
except Exception as e:
print(f"Error loading wallet from private key: {e}")
if __name__ == "__main__":
main()
כיצד להשתמש בכלי CLI זה:
- שמור את הקוד שלעיל כקובץ פייתון (לדוגמה, `cli_wallet.py`).
- פתח את הטרמינל או שורת הפקודה שלך.
- ליצירת ארנק חדש: `python cli_wallet.py create`
- כדי לצפות בפרטים ממפתח פרטי קיים: `python cli_wallet.py details --privatekey YOUR_PRIVATE_KEY_IN_HEX`
שיטות אבטחה מומלצות ושיקולים חשובים
בנינו בהצלחה ארנק בסיסי, אך יישום מוכן לייצור דורש התמקדות עמוקה הרבה יותר באבטחה. הנה כמה נקודות קריטיות שיש לקחת בחשבון.
1. לעולם אל תשמור מפתחות פרטיים בטקסט רגיל
הסקריפט שלנו מדפיס את המפתח הפרטי לקונסולה, וזה מאוד לא מאובטח. ביישום אמיתי, מפתחות פרטיים צריכים להיות מוצפנים במנוחה, תוך שימוש בסיסמה חזקה. יש לפענח אותם רק בזיכרון כאשר הם נדרשים לחתימה. פתרונות מקצועיים משתמשים לעיתים קרובות במודולי אבטחת חומרה (HSMs) או בהעתקים מאובטחים במכשירים להגנת מפתחות.
2. חשיבות האנטרופיה
אבטחת הארנק שלך מתחילה באקראיות (אנטרופיה) המשמשת ליצירת המפתח הפרטי. `os.urandom` הוא מקור טוב ברוב מערכות ההפעלה המודרניות, אך עבור יישומים בעלי ערך גבוה, מפתחים אוספים לעיתים קרובות אנטרופיה ממקורות מרובים כדי להבטיח אי-חיזוי.
3. ביטויי מילים (Mnemonic Phrases) – התקן בתעשייה
גיבוי ידני של מפתחות פרטיים ארוכים בפורמט הקסדצימלי הוא מסורבל ונוטה לשגיאות. התעשייה פתרה זאת באמצעות ארנקים היררכיים דטרמיניסטיים (HD) (המוגדרים ב-BIP-32) וביטויי מילים (BIP-39). ביטוי מילים הוא רצף של 12-24 מילים נפוצות שניתן להשתמש בהן כדי לשחזר באופן דטרמיניסטי את מפתח האב הפרטי שלך ואת כל המפתחות הבאים. זה הופך את גיבוי ושחזור הארנק לידידותיים הרבה יותר למשתמש.
4. זהו כלי חינוכי, לא ארנק ייצור
חשוב לחזור ולהדגיש כי יישום זה הוא מודל מפושט. ארנק בעולם האמיתי צריך לנהל מספר כתובות, ליצור אינטראקציה עם צמתי בלוקצ'יין כדי לקבל יתרות ולבנות עסקאות, לחשב עמלות ולשדר עסקאות חתומות לרשת. הוא זקוק גם לממשק משתמש מאובטח ולטיפול שגיאות חזק.
5. אינטראקציה עם הרשת
הארנק שלנו יכול ליצור מפתחות ולחתום על הודעות, אך אינו יכול לתקשר עם רשת בלוקצ'יין. כדי לבנות יישום מלא, תצטרכו לשלב ספריות שיכולות להתחבר לצמתי בלוקצ'יין באמצעות RPC (קריאה לפרוצדורה מרוחקת). עבור אתריום, `web3.py` היא הספרייה הסטנדרטית. עבור ביטקוין, ניתן להשתמש בספריות כמו `python-bitcoinlib`.
מסקנות וצעדים הבאים
מזל טוב! בנייתם בהצלחה את הליבה הקריפטוגרפית של ארנק מטבעות קריפטוגרפיים באמצעות פייתון. עברנו מהתיאוריה הבסיסית של קריפטוגרפיה במפתח ציבורי/פרטי ליישום מעשי המייצר כתובות תקפות הן לרשתות הביטקוין והן לאתריום.
פרויקט זה מספק בסיס איתן לחקירה מעמיקה יותר של טכנולוגיית הבלוקצ'יין. ראיתם ממקור ראשון שארנק הוא, בליבתו, מערכת מתוחכמת לניהול מפתחות הבנויה על עקרונות קריפטוגרפיים מוכחים.
לאן ממשיכים מכאן? שקול את האתגרים הבאים כצעדים הבאים שלך:
- הטמע ארנקי HD: חקור את תקני BIP-32, BIP-39 ו-BIP-44 כדי ליצור ארנק שיכול לנהל מיליוני כתובות מביטוי אתחול יחיד (mnemonic seed phrase).
- התחבר לרשת: השתמש ב-`web3.py` כדי להתחבר לצומת אתריום (כמו Infura או Alchemy), לבדוק יתרת כתובת ולבנות עסקה גולמית.
- בנה ממשק משתמש: צור ממשק משתמש גרפי (GUI) פשוט באמצעות Framework כמו Tkinter או ממשק אינטרנטי באמצעות Flask/Django כדי להפוך את הארנק שלך לידידותי יותר למשתמש.
- חקור בלוקצ'יינים אחרים: חקור כיצד פלטפורמות בלוקצ'יין אחרות מייצרות את כתובותיהן והתאם את הקוד שלך כדי לתמוך בהן.
עולם הבלוקצ'יין בנוי על שיתוף פעולה בקוד פתוח ועל צימאון לידע. על ידי בניית כלים כאלה, אינכם רק לומדים לקודד – אתם לומדים את שפתה של כלכלה דיגיטלית חדשה. המשיכו להתנסות, המשיכו לבנות, והמשיכו לחקור את הפוטנציאל העצום של טכנולוגיה מבוזרת.